package com.iamdigger.queldorei.registry.zookeeper;

import com.iamdigger.queldorei.common.util.CollectionUtil;
import com.iamdigger.queldorei.registry.ServiceDiscovery;
import org.I0Itec.zkclient.ZkClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 基于 ZooKeeper 的服务发现接口实现
 *
 * @author Sam Tsai
 * @since 0.1.0
 */
public class ZooKeeperServiceDiscovery implements ServiceDiscovery {

    private static final Logger LOGGER = LoggerFactory.getLogger(ZooKeeperServiceDiscovery.class);

    //private String zkAddress; // zk服务器地址
    private String zkRegistryPath;  // 服务注册地址

    private ZkServiceAddressSynchronizer serviceAddressSynchronizer;
    private ZkClient lowLevelClient;

    public ZooKeeperServiceDiscovery(String zkAddress, String zkRegistryPath) {
        this(zkAddress, zkRegistryPath, null);
    }

    /**
     * 增加服务同步辅助工具
     *
     * @param zkAddress   zk地址
     * @param serviceSync 服务同步
     */
    public ZooKeeperServiceDiscovery(String zkAddress, String zkRegistryPath, ZkServiceAddressSynchronizer serviceSync) {
        //this.zkAddress = zkAddress;
        this.zkRegistryPath = zkRegistryPath;
        if (null != serviceSync) {
            this.serviceAddressSynchronizer = serviceSync;
            this.serviceAddressSynchronizer.prepareToSync(zkAddress, zkRegistryPath);
        } else {
            lowLevelClient = new ZkClient(zkAddress, Constant.ZK_SESSION_TIMEOUT, Constant.ZK_CONNECTION_TIMEOUT);
            LOGGER.debug("connect zookeeper");
        }
    }

    @Override
    public String discover(String name) {
        if (null != this.serviceAddressSynchronizer) {
            return discoverFromSynced(name);
        }
        // 获取 service 节点
        String servicePath = zkRegistryPath + "/" + name;
        if (!lowLevelClient.exists(servicePath)) {
            throw new RuntimeException(String.format("can not find any service node on path: %s", servicePath));
        }
        List<String> addressList = lowLevelClient.getChildren(servicePath);
        if (CollectionUtil.isEmpty(addressList)) {
            throw new RuntimeException(String.format("can not find any address node on path: %s", servicePath));
        }
        // 获取 address 节点
        String address;
        int size = addressList.size();
        if (size == 1) {
            // 若只有一个地址，则获取该地址
            address = addressList.get(0);
            LOGGER.debug("get only address node: {}", address);
        } else {
            // 若存在多个地址，则随机获取一个地址
            address = addressList.get(ThreadLocalRandom.current().nextInt(size));
            LOGGER.debug("get random address node: {}", address);
        }
        // 获取 address 节点的值
        String addressPath = servicePath + "/" + address;
        return lowLevelClient.readData(addressPath);
    }

    /**
     * 从本地池中发现服务
     *
     * @param name 服务名
     * @return 服务地址
     */
    private String discoverFromSynced(String name) {
        List<String> serviceAddressGrp = this.serviceAddressSynchronizer.findServiceAddressGrp(name);
        if (null != serviceAddressGrp && serviceAddressGrp.size() > 0) {
            if (serviceAddressGrp.size() == 1) {
                return serviceAddressGrp.get(0);
            } else {
                return serviceAddressGrp.get(ThreadLocalRandom.current().nextInt(serviceAddressGrp.size()));
            }
        }
        return null;
    }

    @SuppressWarnings("unused")
    private Map<String, String> discoverSrvGrpFromSynced(String serviceName) {
        return null;
    }

    @Override
    public Map<String, String> discoverServiceGrp(String serviceName) {
        if(null != this.serviceAddressSynchronizer) {
            return discoverSrvGrpFromSynced(serviceName);
        }

        Map<String, String> addressMap = new HashMap<String, String>();
        // 获取 service 节点
        String servicePath = zkRegistryPath + "/" + serviceName;
        if (!lowLevelClient.exists(servicePath)) {
            LOGGER.error("can not find any service node on path: {}", servicePath);
            return addressMap;
            //throw new RuntimeException(String.format("can not find any service node on path: %s", servicePath));
        }

        List<String> addressList = lowLevelClient.getChildren(servicePath);
        if (CollectionUtil.isEmpty(addressList)) {
            LOGGER.error("can not find any address node on path: {}", servicePath);
            return addressMap;
            //throw new RuntimeException(String.format("can not find any address node on path: %s", servicePath));
        }
        // 获取 address 节点
        for(String address : addressList) {
            addressMap.put(address, (String)lowLevelClient.readData(servicePath + "/" + address, true));
        }
        return addressMap;
    }
}